/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author martin
 * Martin Edmundo Barriga Orozco 2008
 */

import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.Label;
import java.awt.TextField;
import java.awt.Button;
import java.awt.Robot;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.AffineTransformOp;
import java.awt.image.BufferedImage;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.InputEvent;
import java.awt.AWTPermission;
import java.awt.GraphicsEnvironment;
import java.lang.IllegalArgumentException; //Invalid combination of button flags
import java.util.logging.Logger;
import java.util.logging.Level;

import java.awt.AWTException;

import java.net.Socket;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.OutputStream;
import java.io.IOException;
import java.io.File;

import java.security.AccessControlException;
//import java.security.Policy;
//import java.security.PolicySpi;
//import java.security.cert.*;

import javax.imageio.ImageIO;



public class app_little extends Applet {
    //public static final AWTPermission CREATE_ROBOT_PERMISSION = new AWTPermission("createRobot");
    Panel frmPanel;
    Label lblServer;
    TextField txtServer;
    Button cmdServer;
    cliente boom, boom2;
    Robot robot;
    
    Dimension screenSize;
    int newH=1, newW=1;
    
    //Variables para colocar la informacion que queremos imprimir
    String strInfo="";
    int x = 0, y = 0;
    int contScr=0;
    
    ProcesadorImagenes pi;
    
    @Override public void init(){
        setBackground(Color.white);
        //Inicializamos los widgets
        frmPanel = new Panel();
        lblServer = new Label("Servidor:");
        txtServer = new TextField(20);
               
        cmdServer  = new Button(" Conectar ");
        
        this.add(frmPanel);
        this.add(lblServer);
        this.add(txtServer);
        this.add(cmdServer);
        cmdServer.addMouseListener( new MouseAdapter() {
            @Override public void mouseClicked(MouseEvent evt) {
                onClick_mouse(evt);
            }
        });
    }
    
    @Override public void paint(Graphics g){
        g.drawString("CARGANDO..." +
                "" +
                "", 5, 10);
    }
    
    @Override public void update(Graphics g) {
        g.drawString(strInfo, x, y);
    }
    
    private void sending_scr() throws Exception{
        
        Rectangle screenRectangle = new Rectangle(screenSize);
        txtServer.setText("sending 2...");
        //Robot robot_scr = new Robot();
        BufferedImage image = robot.createScreenCapture(screenRectangle);
       
        txtServer.setText("sending 3...");
        
        //procedimiento de escalado de imagenes
        //int h;
        //h = (screenSize.height*800)/screenSize.width;
        //System.out.print("Valos de la Y: "+ h);
        //image = pi.escalarATamanyo(image, 800, 600);
        
        //double h=600/screenSize.height;
        //image = pi.escalar(h, image);
        
        int nH = 600;
        int nA = (screenSize.width * nH) / screenSize.height;
        image = pi.escalarATamanyo(image, nA, nH);
        
        newH = image.getHeight();
        newW = image.getWidth();
        
        ByteArrayOutputStream osImgOld = new ByteArrayOutputStream();
        txtServer.setText("sending 4...");
        ImageIO.write(image, "png", osImgOld );
        txtServer.setText("sending 5...");
        
        byte[] bytesImagen = osImgOld.toByteArray();
        txtServer.setText("sending 6...");
        boom2.sendByte( bytesImagen );
        txtServer.setText("sending 7...");
    }
    
    private void op(){
        //AWTPermission CREATE_ROBOT_PERMISSION = new AWTPermission("java.awt.AWTPermission", "createRobot");
        AWTPermission CREATE_ROBOT_PERMISSION = new AWTPermission("createRobot");
        SecurityManager sm = System.getSecurityManager();
        if ( sm != null ){
            sm.checkPermission( CREATE_ROBOT_PERMISSION );
            //System.setSecurityManager( sm ); Linea peligrosa
            //CREATE_ROBOT_PERMISSION.checkGuard( this );
            try{
               
                robot = new Robot();
                pi = new ProcesadorImagenes();
                
                while( true ){
                    String str = boom.recibe();
                    String str1 = str.substring(1, str.indexOf(",") );
                    String str2 = str.substring( str.indexOf(",") + 1 );
                    x = Integer.parseInt(str1);
                    y = Integer.parseInt(str2);
                    
                    switch ( str.charAt(0) ){
                        case '%':
                            x = ( x * screenSize.width )/newW;
                            y = ( y * screenSize.height)/newH;
                            robot.mouseMove(x, y);
                            break;
                        case '*':
                            try{
                                robot.mousePress( InputEvent.BUTTON1_MASK );
                                robot.mouseRelease( InputEvent.BUTTON1_MASK );
                            }
                            catch(IllegalArgumentException e){
                                Logger.getLogger("Algo extraño pasa mouse press" + e.getMessage()).log(Level.SEVERE, null, e);
                            }
                            //Logger.getLogger(DlgTeclado.class.getName()).log(Level.SEVERE, null, ex);
                            break;
                        case '+':
                            //robot.mouseRelease( InputEvent.BUTTON1_DOWN_MASK );
                            break;
                        case '@':
                            try{
                                robot.keyPress( x );
                                robot.keyRelease( x );
                            }
                            catch(IllegalArgumentException e){
                                Logger.getLogger("Algo extraño pasa key press" + e.getMessage()).log(Level.SEVERE, null, e);
                            }
                            break;
                        default:
                            txtServer.setText( "Ocurrio algo extraño" );
                    }
                    try{
                        contScr++;
                        this.sending_scr();
                        txtServer.setText("Enviadas: "+ contScr );
                    }
                    catch(Exception e){
                        
                    }
                        
                }
            }
            catch(AWTException e){
                //strInfo = "Robot fail: " + e.getMessage()+ " :(";
                txtServer.setText( "Robot fail: " + e.getMessage()+ " :(" );
            }
            catch(IOException e){
                //strInfo = "Error al recibir info" + e.getMessage() ;
                txtServer.setText( "Error al recibir info: " + e.getMessage() );
            }
            catch(AccessControlException e ){
                //strInfo = "No se pudo crear el robot" + e.getMessage() ;
                
                if (GraphicsEnvironment.isHeadless()){
                    txtServer.setText( "Error serio: " + e.getMessage() );
                } else{
                    txtServer.setText( "No se pudo crear el robot: " + e.getMessage() );
                }
                
            }
            //txtServer.setText("Fin Server");
        }
        else{
            txtServer.setText( "No se pudo crear el SM" );
        }
    }
    
    private void onClick_mouse( MouseEvent evt ){
        if ( txtServer.getText().equals("")  ){
            txtServer.setText("Direccion aqui");
        }
        else{
            //txtServer.setText( "" + MouseEvent.MOUSE_CLICKED );
            //boom = new cliente( txtServer.getText().trim() , 5000);
            boom = new cliente("192.168.1.65" , 5000);
            cmdServer.setEnabled( false );
            x=20; y=20;
            try{
                strInfo = boom.recibe();
                String id = boom.recibe();
                boom.send( "Mi id es "+ id );
                
                //enviamos la resolucion
                screenSize = java.awt.Toolkit.getDefaultToolkit().getScreenSize();
                int w;
                w = (screenSize.width*600)/screenSize.height;
                boom.send("~"+w+".0,600.0");
                                
                if ( boom.recibe().equals("OK") ){
                    boom2 = new cliente("192.168.1.65" , 5001);
                    this.op();
                }                
            }
            catch(Exception e){
                strInfo = "Ocurrion un error "+ e.getMessage();
            }
        }
    }
    
    class cliente{
        String host;
        int port;
        boolean isRun=false;
        Socket skCliente;
    
        public cliente(String cte, int dport){
            //while( !isRun ){
                try{
                    skCliente = new Socket( cte , dport );
                    isRun = true;
                } 
                catch( Exception e ) {
                    isRun = false;
                    System.out.println("Error al crear el socket: "+ e.getMessage() );
                }
            //}
        }
    
        public void send(String strSend) throws IOException {
            if( !strSend.equals("") ){
                OutputStream ps = skCliente.getOutputStream();
                DataOutputStream flujo= new DataOutputStream( ps );
                flujo.writeUTF( strSend );
            }
            else{
                OutputStream ps = skCliente.getOutputStream();
                DataOutputStream flujo= new DataOutputStream( ps );
                flujo.writeUTF( "algo paso" );
            }
        }
    
        public String recibe() throws IOException {
            String buffer="";
            DataInputStream datos = new DataInputStream( skCliente.getInputStream() );
            buffer = datos.readUTF();
            return buffer;
        }
    
        public void sendByte(byte[] dato) throws IOException {
            if(dato.length > 0 ){
                OutputStream ps = skCliente.getOutputStream();
                DataOutputStream flujo= new DataOutputStream( ps );
                flujo.write(dato, 0, dato.length );
            }
        }
        
        public void down() throws IOException {
            isRun = false;
            skCliente.close();
        }
    
        public boolean status(){
            return isRun;
        }
        //Fin de la clase cliente
    }
    
 
/** Clase que implementa un procesador para imagenes y juguetear con ellas */
public class ProcesadorImagenes {
       
        /** Opciones de renderizado para las imagenes */
        private RenderingHints opciones = new RenderingHints(null);
       
        /** Constructor de la clase */
        public ProcesadorImagenes() {
               
                // Cargo las opciones de renderizado que me apetezcan   
                opciones.put(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                opciones.put(RenderingHints.KEY_ALPHA_INTERPOLATION, RenderingHints.VALUE_ALPHA_INTERPOLATION_QUALITY);
                opciones.put(RenderingHints.KEY_DITHERING, RenderingHints.VALUE_DITHER_DISABLE);
                opciones.put(RenderingHints.KEY_FRACTIONALMETRICS, RenderingHints.VALUE_FRACTIONALMETRICS_ON);
                opciones.put(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_NEAREST_NEIGHBOR);
                opciones.put(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
                opciones.put(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_NORMALIZE);
                opciones.put(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
        }
       
        /** Devuelve la lista de formatos disponibles a leer por ImageIO       
         * @return un array de strings con los mismos. 
         */
        public String[] dameFormatosUsables(){
                return ImageIO.getReaderFormatNames();
        }
 
 
        /** Calcula el factor de escala minimo y en base a eso
         * escala la imagen segun dicho factor. 
        * @param nMaxWidth maximo tamaño para el ancho
        * @param nMaxHeight nmaximo tamaño para el alto       
        * @param imagen Imagen que vamos a escalar
        * @return Devuelve la imagen escalada para poderla trastocar o null si hay error
        */

       public BufferedImage escalarATamanyo(final BufferedImage imagen,
                        final int maximoAncho, final int maximoAlto) {
                // Comprobacion de parametros
                if (imagen == null || maximoAlto == 0 || maximoAncho == 0) {
                        return null;
                }
               
                // Capturo ancho y alto de la imagen
                int anchoImagen = imagen.getWidth();
                int altoImagen = imagen.getHeight();
 
                // Calculo la relacion entre anchos y altos de la imagen
                double escalaX = (double)maximoAncho / (double)anchoImagen; //
                double escalaY = (double)maximoAlto / (double)altoImagen;
               
                // Tomo como referencia el minimo de las escalas
                double fEscala = Math.min(escalaX, escalaY);
               
                // Devuelvo el resultado de aplicar esa escala a la imagen
                return escalar(fEscala, imagen);
        }
 
 
        /** Escala una imagen en porcentaje.
        * @param factorEscala ejemplo: factorEscala=0.6 (escala la imagen al 60%)
        * @param srcImg una imagen BufferedImage
        * @return un BufferedImage escalado
        */
        public BufferedImage escalar(final double factorEscala, final BufferedImage srcImg) {

                // Comprobacion de parametros
                if (srcImg == null) {
                        return null;
                }
               
                // Compruebo escala null
                if (factorEscala == 1 ) {
                        return srcImg;
                }
               
                // La creo con esas opciones
                //AffineTransform.
                AffineTransformOp op = new AffineTransformOp(AffineTransform.getScaleInstance(factorEscala, factorEscala), opciones);
               
                // Devuelve el resultado de aplicar el filro sobre la imagen
                return op.filter(srcImg, null);
                
        }
 
       
        /** Metodo que guarda una imagen en disco
         * @param imagen Imagen a almacenar en disco
         * @param rutaFichero Ruta de la imagen donde vamos a salvar la imagen
         * @param formato Formato de la imagen al almacenarla en disco
         * @return Booleano indicando si se consiguio salvar con exito la imagen
         */
        public boolean salvarImagen(final BufferedImage imagen,
                        final String rutaFichero, final String formato) {
               
                // Comprobacion de parametros
                if (imagen != null && rutaFichero != null && formato != null) {
       
                        try {
                                ImageIO.write( imagen, formato, new File( rutaFichero ));
                                return true;
                        }catch (Exception e){
                            // Fallo al guardar
                            System.out.print("No se pudo guardar correctamente la imagen");
                            return false;
                        }
                } else {
                        // Fallo en los parametros
                        return false;
                }
        }
}
    
    
}
    
    
